package com.tj.api.rest.user;

import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.base.services.redis.TimeConsts;
import com.fqgj.common.api.annotations.ParamsValidate;
import com.fqgj.common.utils.DES;
import com.fqgj.common.utils.DateUtil;
import com.fqgj.common.utils.RandomUtil;
import com.fqgj.common.utils.StringUtils;
import com.fqgj.exception.common.ApplicationException;
import com.tj.api.annotations.VisitorAccessible;
import com.tj.api.rest.user.request.UserAuthRequest;
import com.tj.api.rest.user.request.UserReadPopupRequest;
import com.tj.api.rest.user.request.UserSocialLoginRequest;
import com.tj.api.rest.user.response.*;
import com.tj.bo.account.client.CreateAccountService;
import com.tj.bo.account.client.enums.AccountTypeEnum;
import com.tj.bo.account.client.vo.CreateAccountVO;
import com.tj.bo.common.conf.api.ApiResponse;
import com.tj.bo.common.conf.config.RedisConfigUtil;
import com.tj.bo.common.conf.constant.RedisKey;
import com.tj.bo.common.conf.enums.RestCodeEnum;
import com.tj.bo.common.conf.util.HttpUtil;
import com.tj.bo.common.conf.util.ShareCodeUtils;
import com.tj.bo.integration.MessageIntegrationService;
import com.tj.bo.user.client.UserCheckService;
import com.tj.bo.user.client.UserLoginService;
import com.tj.bo.user.client.UserPromotionService;
import com.tj.bo.user.client.UserQueryService;
import com.tj.bo.user.client.enums.EmailTypeEnum;
import com.tj.bo.user.client.enums.UserRegisterTypeEnum;
import com.tj.bo.user.client.vo.input.UserLogoutInput;
import com.tj.bo.user.client.vo.output.UserAccessInfoRO;
import com.tj.bo.user.client.vo.output.UserPromotionMappingInfo;
import com.tj.template.application.user.UserBaseApplication;
import com.tj.template.application.user.input.*;
import com.tj.template.application.user.output.*;
import com.tj.template.config.vo.RequestBasicInfo;
import com.tj.template.config.vo.RequestLocalInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created with IntelliJ IDEA.
 * User: binary
 * Date: 2020/6/9
 * Time: 下午4:35
 */
@RestController
@RequestMapping("/user")
public class UserController {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserBaseApplication userBaseApplication;

    @Autowired
    private MessageIntegrationService messageIntegrationService;

    @Autowired
    private CreateAccountService createAccountService;

    @Autowired
    private UserLoginService userLoginService;

    @Autowired
    private UserCheckService userCheckService;

    @Autowired
    private UserQueryService userQueryService;
    @Autowired
    private RedisClient redisClient;
    @Autowired
    private RedisConfigUtil redisConfigUtil;
    @Autowired
    private UserPromotionService userPromotionService;

    /**
     * 初始化接口
     *
     * @return
     */
    @VisitorAccessible
    @RequestMapping(value = "/init")
    @ParamsValidate
    public ApiResponse<UserInitResponse> init() {
        UserInitApOutput userInitAppOutput = userBaseApplication.init();
        if (userInitAppOutput.isDeviceDemoRegister()) {
            CreateAccountVO createAccountVO = new CreateAccountVO();
            createAccountVO.setUserCode(userInitAppOutput.getDemoUserCode());
            createAccountVO.setAccountTypeEnum(AccountTypeEnum.DEMO);
            createAccountService.createAccount(createAccountVO);
        }

        UserInitResponse userInitResponse = new UserInitResponse();
        userInitResponse.setRealToken(userInitAppOutput.getRealToken());
        return new ApiResponse<>(userInitResponse);
    }

    /**
     * 邮箱注册
     *
     * @return
     */
    @VisitorAccessible
    @RequestMapping(value = "/register")
    @ParamsValidate
    public ApiResponse<UserRegisterResponse> register(@RequestBody UserRegisterApInput request) {
        verifyEmail(request.getEmail());
        UserRegisterApOutput userRegisterResponse = userBaseApplication.register(request);

        CreateAccountVO createAccountVO = new CreateAccountVO();
        createAccountVO.setUserCode(userRegisterResponse.getRealUserCode());
        createAccountVO.setAccountTypeEnum(AccountTypeEnum.REAL);
        createAccountVO.setUserName("");
        createAccountVO.setMobile("");
        createAccountVO.setOperator("");
        createAccountService.createAccount(createAccountVO);

        CreateAccountVO createAccountVODemo = new CreateAccountVO();
        createAccountVODemo.setUserCode(userRegisterResponse.getDemoUserCode());
        createAccountVODemo.setAccountTypeEnum(AccountTypeEnum.DEMO);
        createAccountVODemo.setUserName("");
        createAccountVODemo.setMobile("");
        createAccountVODemo.setOperator("");
        createAccountService.createAccount(createAccountVODemo);

        return new ApiResponse<>(new UserRegisterResponse(userRegisterResponse.getRealToken()));
    }

    /**
     * H5推广注册
     * @param request
     * @return
     */
    @VisitorAccessible
    @RequestMapping(value = "/promotion/register")
    @ParamsValidate
    public ApiResponse<UserRegisterResponse> promotionRegister(@RequestBody UserPromotionRegisterRequest request) {

        if(request.getType() == UserRegisterTypeEnum.EMAIL.getType()){
            verifyEmail(request.getLoginAccount());
            String emailCacheVerifyCode = redisClient.get(RedisKey.SIGN_EMAIL_VERIFY_CODE_REDIS_KEY_PREFIX, request.getLoginAccount());
            if(redisConfigUtil.isTest()){
                emailCacheVerifyCode = "123456";
            }
            if(!request.getVerifyCode().equalsIgnoreCase(emailCacheVerifyCode)){
                throw new ApplicationException("Please enter the correct email Verification Code.");
            }
        }

        UserPromotionMappingInfo userPromotionMappingInfo = userPromotionService.queryUserPromotionInfoByUserId(ShareCodeUtils.codeToId(request.getInviteCode()));
        if(request.getInviteCode().length() < 6 || userPromotionMappingInfo == null){
            throw new ApplicationException("The invitation code is invalid");
        }

        UserRegisterApOutput userRegisterResponse = userBaseApplication.promotionRegister(request.getType(), request.getLoginAccount(), request.getPassword(), request.getVerifyCode(), request.getInviteCode());
        return new ApiResponse<>(new UserRegisterResponse(userRegisterResponse.getRealToken(), redisConfigUtil.getGooglePlayUrl())).setMsg("Login Success");
    }

    /**
     * 注册协议接口
     *
     * @return
     */
    @VisitorAccessible
    @RequestMapping(value = "/protocol/get", method = RequestMethod.POST)
    public ApiResponse<RegisterProtocolResponse> getRegisterProtocal() {
        RegisterProtocolApOutput apOutput = userBaseApplication.getProtocol();
        return new ApiResponse<>(new RegisterProtocolResponse(apOutput.getRegisterProtocol()));
    }

    /**
     * 密码登录
     *
     * @return
     */
    @VisitorAccessible
    @RequestMapping(value = "/password/login")
    @ParamsValidate
    public ApiResponse<UserPasswordLoginResponse> passwordLogin(@RequestBody UserPasswordLoginApInput request) {
        verifyEmail(request.getEmail());
        UserPasswordLoginApOutput userPasswordLoginApOutput = userBaseApplication.passwordLogin(request);
        return new ApiResponse<>(new UserPasswordLoginResponse(userPasswordLoginApOutput.getRealToken()));
    }

    /**
     * 社交登录
     *
     * @return
     */
    @VisitorAccessible
    @RequestMapping(value = "/social/login")
    @ParamsValidate
    public ApiResponse<UserSocialLoginResponse> socialLogin(@RequestBody UserSocialLoginRequest request) {
        UserSocialLoginApInput input = new UserSocialLoginApInput();
        BeanUtils.copyProperties(request, input);
        input.setNickname(request.getName());
        UserSocialLoginApOutput userSocialLoginOutput = userBaseApplication.socialLogin(input);

        UserSocialLoginResponse response = new UserSocialLoginResponse()
                .setRealToken(userSocialLoginOutput.getRealToken())
                .setRegister(0);

        if (userSocialLoginOutput.isSocialRegister()) {
            CreateAccountVO createAccountVO = new CreateAccountVO();
            createAccountVO.setUserCode(userSocialLoginOutput.getRealUserCode());
            createAccountVO.setAccountTypeEnum(AccountTypeEnum.REAL);
            createAccountVO.setUserName("");
            createAccountVO.setMobile("");
            createAccountVO.setOperator("");
            createAccountService.createAccount(createAccountVO);

            CreateAccountVO createAccountVODemo = new CreateAccountVO();
            createAccountVODemo.setUserCode(userSocialLoginOutput.getDemoUserCode());
            createAccountVODemo.setAccountTypeEnum(AccountTypeEnum.DEMO);
            createAccountVODemo.setUserName("");
            createAccountVODemo.setMobile("");
            createAccountVODemo.setOperator("");
            createAccountService.createAccount(createAccountVODemo);

            response.setRegister(1);
        }

        return new ApiResponse<>(response);
    }

    /**
     * 登出
     *
     * @return
     */
    @RequestMapping(value = "/logout")
    @ParamsValidate
    public ApiResponse logout() {
        RequestBasicInfo requestBasicInfo = RequestLocalInfo.getRequestBasicInfo();
        String userCode = RequestLocalInfo.getCurrentUser().getUserCode();

        UserLogoutInput userLogoutInput = new UserLogoutInput();
        userLogoutInput.setUserCode(userCode);
        userLogoutInput.setDeviceId(requestBasicInfo.getDeviceId());
        userLogoutInput.setAppCode(requestBasicInfo.getAppCode());
        userLogoutInput.setPackageName(requestBasicInfo.getPackageName());
        userLogoutInput.setClientId(requestBasicInfo.getClientId());
        userLogoutInput.setPlatform(requestBasicInfo.getPlatform());
        userLogoutInput.setVersion(requestBasicInfo.getAppVersion());
        userLogoutInput.setVersionCode(requestBasicInfo.getVersionCode());
        userLogoutInput.setChannel(requestBasicInfo.getChannel());
        userLogoutInput.setIp(requestBasicInfo.getIp());

        userLoginService.userLogout(userLogoutInput);
        return new ApiResponse<>();
    }

    /**
     * 发送邮件
     *
     * @return
     */
    @VisitorAccessible
    @RequestMapping(value = "/email/send")
    @ParamsValidate
    public ApiResponse emailSend(@RequestBody EmailSendApInput request) {

        verifyEmail(request.getEmail());

        if(!redisClient.setnx(RedisKey.SEND_EMAIL_CODE_MULTIPLY_LIMIT, request.getEmail(), request.getEmail())){
            throw new ApplicationException("Too many times to send. Please try again in a minute.");
        }
        redisClient.expire(RedisKey.SEND_EMAIL_CODE_MULTIPLY_LIMIT, TimeConsts.ONE_MINUTE, request.getEmail());
        String appCode = RequestLocalInfo.getRequestBasicInfo().getAppCode();
        EmailTypeEnum emailTypeEnum = EmailTypeEnum.getEnum(request.getType());
        if(emailTypeEnum == null){
            throw new ApplicationException("email type is invalid");
        }
        if (EmailTypeEnum.FORGET_LOGIN_PASSWORD.equals(emailTypeEnum)) {
            if (!userCheckService.isEmailRegistered(appCode, request.getEmail())) {
                throw new ApplicationException(RestCodeEnum.USER_NOT_EXIST_ERROR, "The email is not registered");
            }

            UserAccessInfoRO userAccessInfo = userQueryService.getUserAccessInfo(request.getEmail());

            String password = null;
            try {
                password = DES.decrypt(userAccessInfo.getPassWord());
            } catch (Exception e) {
                password = userAccessInfo.getPassWord();
            }

            String content = HttpUtil.getPage("http://oss.abctradeapp.com/email/basicTemplate.html");
            content = content.replace("__content__", password);
            content = content.replace("__Date__", DateUtil.getDate(new Date(), "dd/MM/yyyy"));
            messageIntegrationService.sendEmail(request.getEmail(), content, "Retrieve Password");
        }else if(EmailTypeEnum.EMAIL_LOGIN_BY_VERIFY_CODE.equals(emailTypeEnum)){
            //验证码先从缓存中获取 有的话就不要重新生成
            String redisVerifyCode = redisClient.get(RedisKey.SIGN_EMAIL_VERIFY_CODE_REDIS_KEY_PREFIX, request.getEmail());
            String verifyCode = StringUtils.isEmpty(redisVerifyCode) ? RandomUtil.getVerifyCode(6) : redisVerifyCode;
            if (redisConfigUtil.isTest()) {
                verifyCode = "123456";
            }
            LOGGER.info("sendVerifyCode,email:{},loginVerifyCode is {}", request.getEmail(), verifyCode);
            String content = HttpUtil.getPage("http://oss.abctradeapp.com/email/basicTemplate_email_verifyCode.html");
            content = content.replace("__content__", verifyCode);
            content = content.replace("__Date__", DateUtil.getDate(new Date(), "dd/MM/yyyy"));
            messageIntegrationService.sendEmail(request.getEmail(), content, "Email Login");
            redisClient.set(RedisKey.SIGN_EMAIL_VERIFY_CODE_REDIS_KEY_PREFIX, verifyCode, TimeConsts.FIVE_MINUTES, request.getEmail());
            return new ApiResponse<>().setMsg("Please check email code");
        }
        return new ApiResponse<>().setMsg("Email sent successfully");
    }

    public static void main(String[] args) {
        String content = HttpUtil.getPage("https://oss.abctradeapp.com/email/basicTemplate.html");
        content = content.replace("__content__", "AbcTrade warm reminder, your current password is 123");
        content = content.replace("__Date__", DateUtil.getDate(new Date(), "dd/MM/yyyy"));
        System.out.println(content);
    }

    /**
     * 设置新密码
     *
     * @return
     */
    @VisitorAccessible
    @RequestMapping(value = "/password/reset")
    @ParamsValidate
    public ApiResponse passwordReset(@RequestBody UserPasswordResetApInput request) {
        verifyEmail(request.getEmail());
        userBaseApplication.passwordReset(request);
        return new ApiResponse<>();
    }

    /**
     * 我的页面信息
     *
     * @return
     */
    @VisitorAccessible
    @RequestMapping(value = "/info/get")
    @ParamsValidate
    public ApiResponse passwordReset() {
        return new ApiResponse<>(userBaseApplication.getUserMyInfo());
    }

    private void verifyEmail(String email) {
        if (StringUtils.isEmpty(email)) {
            throw new ApplicationException("Email can't be empty");
        }
        String check = "^[A-Za-z0-9]+([_\\.][A-Za-z0-9]+)*@([A-Za-z0-9\\-]+\\.)+[A-Za-z]{2,6}$";
        Pattern regex = Pattern.compile(check);
        Matcher matcher = regex.matcher(email);
        if (!matcher.matches()) {
            LOGGER.warn("邮箱格式错误,email:{}", email);
            throw new ApplicationException("Email format error");
        }
    }

    /**
     * 我的页面信息
     *
     * @return
     */
    @VisitorAccessible
    @RequestMapping(value = "/promotion/getInviteBonus")
    public ApiResponse<UserPromotionInviteResponse> getInviteBonus() {
        return new ApiResponse<>(userBaseApplication.getInviteBonus());
    }

    /**
     * 获取邀请记录
     * @return
     */
    @RequestMapping(value = "/promotion/invite/record")
    public ApiResponse<UserPromotionRecordResponse> getInviteRecord() {
        return new ApiResponse<>(userBaseApplication.getInviteRecord());
    }

    /**
     * 用户弹窗
     * @return
     */
    @RequestMapping(value = "/activity/popup", method = RequestMethod.POST)
    public ApiResponse<UserActivityPopupResponse> popup() {

        UserActivityPopupResponse userActivityPopupResponse = null;
        UserActivityPopupVO userActivityPopup = userBaseApplication.popup();
        if(userActivityPopup != null){
            userActivityPopupResponse = new UserActivityPopupResponse(userActivityPopup);
        }
        return new ApiResponse<>(userActivityPopupResponse).setMsg("Popup Success");
    }

    /**
     * 已读弹窗
     * @param userReadPopupRequest
     * @return
     */
    @ParamsValidate
    @RequestMapping(value = "/activity/popup/read", method = RequestMethod.POST)
    public ApiResponse readPopup(@RequestBody @Valid UserReadPopupRequest userReadPopupRequest) {
        userBaseApplication.readPopup(userReadPopupRequest.getPopupId());
        return new ApiResponse<>("Read Success");
    }

    /**
     * 获取banner
     * @return
     */
    @VisitorAccessible
    @RequestMapping(value = "/banners", method = RequestMethod.POST)
    public ApiResponse<UserBannersResponse> getBanners() {
        return new ApiResponse<>(new UserBannersResponse(userBaseApplication.getBanners()));
    }

    /**
     * 用户认证
     * @param userAuthRequest
     * @return
     */
    @ParamsValidate
    @RequestMapping(value = "/authentication", method = RequestMethod.POST)
    public ApiResponse saveUserInfo(@RequestBody @Valid UserAuthRequest userAuthRequest) {
        userBaseApplication.saveUserInfo(userAuthRequest.getName(), userAuthRequest.getMobile(), userAuthRequest.getEmail());
        return new ApiResponse<>();
    }

    /**
     * 获取用户认证信息
     * @return
     */
    @RequestMapping(value = "/authentication/info", method = RequestMethod.POST)
    public ApiResponse<UserAuthenticationResponse> getUserAuthenticationInfo() {
        return new ApiResponse<>(new UserAuthenticationResponse(userBaseApplication.getUserAuthenticationInfo()));
    }


}
